package gsp

import (
	"errors"
	"reflect"
	"strconv"
	"time"
)

var errUnknownType = errors.New("unknown type")

func arrayToMap(keys []string, values []string) map[string]string {
	if len(keys) != len(values) {
		panic(errors.New("keys and values len not equal"))
	}
	data := make(map[string]string)

	for i := 0; i < len(keys); i++ {
		data[keys[i]] = values[i]
	}

	return data
}

func setIntField(val string, bitSize int, field reflect.Value) error {
	if val == "" {
		val = "0"
	}
	intVal, err := strconv.ParseInt(val, 10, bitSize)
	if err == nil {
		field.SetInt(intVal)
	}
	return err
}
func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
	d, err := time.ParseDuration(val)
	if err != nil {
		return err
	}
	value.Set(reflect.ValueOf(d))
	return nil
}

func setUintField(val string, bitSize int, field reflect.Value) error {
	if val == "" {
		val = "0"
	}
	uintVal, err := strconv.ParseUint(val, 10, bitSize)
	if err == nil {
		field.SetUint(uintVal)
	}
	return err
}

func setBoolField(val string, field reflect.Value) error {
	if val == "" {
		val = "false"
	}
	boolVal, err := strconv.ParseBool(val)
	if err == nil {
		field.SetBool(boolVal)
	}
	return err
}

func setFloatField(val string, bitSize int, field reflect.Value) error {
	if val == "" {
		val = "0.0"
	}
	floatVal, err := strconv.ParseFloat(val, bitSize)
	if err == nil {
		field.SetFloat(floatVal)
	}
	return err
}

func mapping(field reflect.StructField, val reflect.Value, v string) error {
	// 根据类型来设置值
	switch fieldType := field.Type.Kind(); fieldType {
	case reflect.Int:
		return setIntField(v, 0, val)
	case reflect.Int8:
		return setIntField(v, 8, val)
	case reflect.Int16:
		return setIntField(v, 16, val)
	case reflect.Int32:
		return setIntField(v, 32, val)
	case reflect.Int64:
		switch val.Interface().(type) {
		case time.Duration:
			return setTimeDuration(v, val, field)
		}
		return setIntField(v, 64, val)
	case reflect.String:
		val.SetString(v)
	case reflect.Uint:
		return setUintField(v, 0, val)
	case reflect.Uint8:
		return setUintField(v, 8, val)
	case reflect.Uint16:
		return setUintField(v, 16, val)
	case reflect.Uint32:
		return setUintField(v, 32, val)
	case reflect.Uint64:
		return setUintField(v, 64, val)
	case reflect.Bool:
		return setBoolField(v, val)
	case reflect.Float32:
		return setFloatField(v, 32, val)
	case reflect.Float64:
		return setFloatField(v, 64, val)
	default:
		return errUnknownType
	}
	return nil
}

// Strval 获取变量的字符串值
// 浮点型 3.0将会转换成字符串3, "3"
// 非数值或字符类型的变量将会被转换成JSON格式字符串
func Strval(value interface{}) string {
	// interface 转 string
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
	}

	return key
}